######################################################################
# Time-stamp: <05/09/09 11:06:22 ostolop>
######################################################################
package EP::EPC::Core::Data_Management;

use strict;

use EP::Config;

use EP::Common;
use EP::Common::DBI::Dataset;
use EP::Common::DBI::Folder;
use EP::Common::DBI::Action;

use EP::Common::DB;
use EP::Common::Data;
use EP::Common::Error qw ( :try );
use EP::Common::General;

use EP::EPC::Core::Component;

use Carp;
use Carp qw (cluck);

use PDL;
use PDL::NiceSlice;

our @ISA = qw ( EP::EPC::Core::Component );

sub process_component {
  my $self = shift;
  my $process_result;

  $self->process_data_management ();
  $process_result = {};

  $self->{CD}->{process_result} = $process_result;
  return OK;
}

sub process_data_management {
  my $self = shift;

  if ( $self->{query}->param('action') eq 'new_folder' ) {
    $self->create_folder();
  } elsif ( $self->{query}->param('action') eq 'delete_folder' ) {
    $self->delete_folder();
  } elsif ( $self->{query}->param('action') eq 'delete_dataset' ) {
    $self->delete_dataset();
  } elsif ( $self->{query}->param('action') eq 'delete_action' ) {
    $self->delete_action();
  } elsif ( $self->{query}->param('action') eq 'delete_selection' ) {
    $self->delete_action();
    $self->delete_dataset();
    $self->delete_folder();
  } elsif ( $self->{query}->param('action') eq 'saveas_action' ) {
    $self->export_dataset();
  }
}

######################################################################
# Remove root_dataset and associated siblings from disk and db
######################################################################
sub delete_dataset {
  my $self = shift;

  my @pnames = $self->{query}->param;
  my @dataset_ids = map { /chk_dataset_(\d+)/ } grep { /^chk_dataset/ } @pnames;

  foreach my $id ( @dataset_ids ) {
    my $dataset = retrieve EP::Common::DBI::Dataset ( $id );
#    my $dataset = ${ EP::Common::DB::get_dataset( { id => $id } ) }{0};
#    my $folder = EP::Common::DB::get_folder( { id => $dataset->{folder_id} } );

    next if not $dataset;
    warn "Going to delete " . $dataset->name  if DEBUG;
    $self->{session}->status ( "Deleting dataset ..." );
    if ( $dataset->folder->owner == $self->{current_user} ) {
      if ( $dataset->id == $self->{session}->current_root_dataset ) {
	my ($first_dataset) = EP::Common::DBI::Dataset->search_where ( { owner => $self->{current_user}, folder => $self->{session}->current_folder },
								       { order_by => 'created' } );
	$self->{session}->current_root_dataset ( $first_dataset );
	$self->{session}->current_action ( undef );
      }

      # delete all files associated with this dataset on disk
      EP::Common::Data::delete_dataset ( $dataset->id );

      # update the database
      $dataset->delete;

    }
  }
}

######################################################################
# Remove root_dataset and associated siblings from disk and db
######################################################################
sub delete_action {
  my $self = shift;

  my @pnames = $self->{query}->param;
  my @action_ids = map { /chk_action_(\d+)/ } grep { /^chk_action/ } @pnames;

  foreach my $id ( @action_ids ) {
    my $action = retrieve EP::Common::DBI::Action ( $id );
    next if not $action;

    if ( $self->{session}->current_action && $self->{session}->current_action->id == $id ) {
      $self->{session}->current_action ( undef );
    }

    warn "Going to delete action $id" if DEBUG;
    $self->{session}->status ( "Deleting action ..." );

    # delete all files associated with this action on disk
    EP::Common::Data::delete_action ( $action );

    # update the database
    $action->delete;
  }
}

######################################################################
# Remove folder and subfolders/datasets from disk and db
######################################################################
sub delete_folder {
  my $self = shift;

  my @pnames = $self->{query}->param;
  my @folder_ids = map { /chk_folder_(\d+)/ } grep { /^chk_folder/ } @pnames;

  my $root_folder = EP::Common::DBI::Folder->search ( { parent => undef } );

  $self->{session}->status ( "Deleting folders and their contents ..." );

  foreach my $id ( @folder_ids ) {
    my $folder = retrieve EP::Common::DBI::Folder ( $id );

    # Does the folder exists and do I have the appropriate rights
    # also set current_folder_id to parent dir and reset current_root_dataset_id and current_action_id
    if ( $folder and $folder->owner eq $self->{current_user} ) {

      if ( $folder->parent == $root_folder  ) {
	# You cannot delete your home directory
	throw EP::Common::Error ( -value => CUD_CANNOT_DELETE_HOME_FOLDER );
      } else {
	if ( $self->{session}->current_folder->id == $folder->id ) {
	  $self->{session}->current_folder ( $folder->parent );
	  my $first_dataset = pop @{EP::Common::DBI::Dataset->search_where ( { owner => $self->{current_user}, folder => $self->{session}->current_folder },
									     { order_by => 'created' } )};
	  $self->{session}->current_root_dataset ( undef );
	  $self->{session}->current_action ( undef );
	}
	
	# delete the directory structure on disk
	EP::Common::Data::delete_folder( $folder->location );
	
	# update the database
	$folder->delete;
      }
    }
  }
}

sub convert_url_to_path {
   my $url = shift;

   my $path = $url;
   
   # check if we deal with /tmp data
   my $tmp_url_base = "$EP::Config::h->{HTML_HREF}/tmp";
   $tmp_url_base =~ s/\//\\\//g;

   if ($url =~ /^$tmp_url_base/) {
       my $tmp_path_base = "$EP::Config::h->{HTML_ROOT}/tmp";

       $path =~ s/$tmp_url_base/$tmp_path_base/;
       return $path;
   }

   my $data_url_base = $EP::Config::h->{EPNG_DATA_URL};
   $data_url_base =~ s/\//\\\//g;

   if ($url =~ /^$data_url_base/) {
       my $data_path_base = $EP::Config::h->{EPNG_DATA_PATH};

       $path =~ s/$data_url_base/$data_path_base/;
       return $path;
   }
}

# sub: export_dataset
#   Exports selected item as a new dataset
sub export_dataset {
  my $self = shift;
  my ( $meta_id ) = @_;

  if ( not $meta_id ) {
    my @pnames = $self->{query}->param;
    ( $meta_id ) = map { /chk_meta_(\d+)/ } grep { /^chk_meta/ } @pnames;
  }

  my $metadata = EP::Common::DBI::Action_Metadata->retrieve ( $meta_id );
  my $dataset;

  # TODO: refactor this idea throughout
  if ( $metadata->type eq 'text/plain' and $metadata->name =~ 'clustering_\d+' ) {
    # deriving a new dataset from a k-means clustering dataset
    my $old_dataset = $metadata->action->dst_dataset;
	my $rows = $old_dataset->data->rows;

	my $cmd = "cat " . convert_url_to_path($metadata->value) . " | head -n1";

    chomp ( my $members_line = `$cmd` );
    my ( $m ) = $members_line =~ /CLUSTER MEMBERS: (.*)/;

    my $members = pdl ( split /,/, $m );
	my $not_members = which ( not ( sequence ( scalar keys %$rows )->in ( $members ) ) );

	delete $rows->{$_} foreach ( list $not_members);
    my $matrix = $old_dataset->data->raw_data;
	my $selpdl = $matrix (:,$members);
	$old_dataset->data->{matrix} = $selpdl;

	$dataset = $old_dataset->copy ( {name => undef} );
	$dataset->data ( $old_dataset->data );
	EP::Core::Data::Parser::exp::user->_write_dataset_data ( $dataset, $dataset->data );
  } else {
	$self->{query}->param ( 'src_url', convert_url_to_path($metadata->value) );
	$self->{query}->param ( 'dataset_name', $metadata->label . " (D)" );
        $self->{query}->param ( 'dataset_species', $metadata->action->dst_dataset->species );
	my $parser = EP::Core::Data::Parser::Factory->create_data_parser ( data_type  => "exp::xml_table",
																	   query      => $self->{query},
																	   caller_epc => $self ) if $metadata->action->dst_dataset->type eq "exp";

	$parser  = EP::Core::Data::Parser::Factory->create_data_parser ( data_type  => "seq::xml_table",
																	 query      => $self->{query},
																	 caller_epc => $self ) if $metadata->action->dst_dataset->type eq "seq";

	$dataset = $parser->parse_data ();
  }

  $dataset->name(undef);
  $dataset->data->process_metadata();

  my $new_action_elts = { component     => 18, # EPC Data Management
			  dst_dataset   => $dataset,
			  root_dataset  => $self->{session}->current_root_dataset,
			  parent_action => $metadata->action
			};
  my $new_action = EP::Common::DBI::Action->create ( $new_action_elts );
  $self->{session}->current_action ( $new_action );

  return $new_action;
}

sub create_folder {
  my $self = shift;

  my $query = $self->{query};
  my $parent_folder = retrieve EP::Common::DBI::Folder ( $query->param ( 'new_folder_parent' ) );

  $self->{session}->status ( "Creating new folder ..." );

  my $new_location = EP::Common::Data::get_valid_foldername ( $parent_folder->location, $query->param('folder') );
  EP::Common::DBI::Folder->create ( { name     => $query->param ( "folder" ),
				      location => $new_location,
				      parent   => $parent_folder,
				      owner    => $self->{current_user},
				      group_write => 0,
				      group_read => 1,
				      other_read => 0
				    } );

  # Folder already exists
#  throw EP::Common::Error( -value => CUD_FOLDER_NAME_EXISTS );
}

1;
